// 版权所有2011 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package xml

import (
	"bufio"
	"bytes"
	"encoding"
	"fmt"
	"io"
	"reflect"
	"strconv"
	"strings"
)

const (
	// Header是一个通用的XML头，适合用于Marshal的输出。
	// 这不会自动添加到此包的任何输出中，
	// 它是为了方便而提供的。
	Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
)

// marshall返回v的XML编码。
// 
// marshall通过封送每个元素来处理数组或片。
// 封送通过封送指针指向的值来处理指针，或者，如果
// 指针为零，则不写入任何内容。Marshall通过
// 对其包含的值进行封送处理，或者，如果接口值为零，则通过
// 不写入任何内容来处理。Marshall通过写入一个或多个包含数据的XML 
// 元素来处理所有其他数据。
// 
// XML元素的名称按优先顺序取自：
// /-XMLName字段上的标记，如果数据是一个结构
// /-类型名称
// /-用于获取数据的结构字段的标记
// /-用于获取数据的结构字段的名称
// /-封送类型的名称
// 
// 结构的XML元素包含封送的元素对于结构的每个
// 导出字段，除了以下例外：
// -省略上述XMLName字段。
// /-省略了带有标记“-”的字段。
// -标记为“name，attr”的字段将成为一个属性，该属性在XML元素中的给定名称为
// 。
// -带有标记“attr”的字段将成为XML元素中带有
// 字段名的属性。
// -带有标记“chardata”的字段被写为字符数据，而不是XML元素。
// -带有标记“cdata”的字段被写入字符数据
// /包装在一个或多个<<中！[CDATA[…]>标记，而不是作为XML元素。
// -带有标记“innerxml”的字段是逐字写入的，不受
// 的常规封送处理程序的约束。
// -带有标记“comment”的字段是作为XML注释编写的，而不是
// /遵循通常的封送处理过程。它不能包含
// 字符串“-”。
// -如果字段值为空，则带有包含“ompitempty”选项的标记的字段将被忽略。空值为false、0、任何
// 零指针或接口值，以及任何长度为零的数组、切片、映射或
// 字符串。
// -匿名结构字段的处理方式与其
// 值的字段是外部结构的一部分一样。
// -通过调用其MarshalXML 
// 方法来编写实现封送器的字段。
// /-实现编码的字段。TextMarshaler是通过将其MarshalText方法的
// 结果编码为text编写的。
// 
// 如果一个字段使用标记“a>b>c”，那么元素c将嵌套在
// 父元素a和b中。名称为
// 相同父元素的相邻字段将包含在一个XML元素中。
// 
// 如果结构字段的XML名称由字段标记和
// 结构的XMLName字段定义，则名称必须匹配。
// 
// 有关示例，请参见MarshalIndent。如果要求封送通道、函数或映射，则封送将返回错误。
func Marshal(v any) ([]byte, error) {
	var b bytes.Buffer
	if err := NewEncoder(&b).Encode(v); err != nil {
		return nil, err
	}
	return b.Bytes(), nil
}

// 封送器是由对象实现的接口，可以将
// 自身封送到有效的XML元素中。
// 
// MarshallXML将接收方编码为零个或多个XML元素。
// 按照惯例，数组或切片通常被编码为元素序列
// 每个条目一个。
// 不需要使用start作为元素标记，但这样做将使Unmarshal能够将XML元素与正确的
// 结构字段相匹配。
// 一种常见的实现策略是构造一个单独的
// 值，其布局对应于所需的XML，然后
// 使用e.EncodeElement对其进行编码。
// 另一种常见策略是重复调用e.EncodeToken 
// 一次生成一个标记的XML输出。
// 编码标记的序列必须组成零个或更多有效的
// XML元素。
type Marshaler interface {
	MarshalXML(e *Encoder, start StartElement) error
}

// MarshalerATR是由对象实现的接口，可以将
// 自身封送到有效的XML属性中。
// 
// MarshallXmlAttr返回一个带有接收方编码值的XML属性。
// 不需要使用name作为属性名，但这样做将使Unmarshal能够将属性与正确的
// 结构字段相匹配。
// 如果MarshalXMLAttr返回零属性Attr{}，则输出中不会生成属性
// 。
// MarshallXmlAttr仅用于字段标记中带有
// “attr”选项的结构字段。
type MarshalerAttr interface {
	MarshalXMLAttr(name Name) (Attr, error)
}

// MarshalIndent的工作原理与Marshal类似，但每个XML元素都从一个新的
// 缩进行开始，该行以前缀开头，后面跟着一个或多个
// 根据嵌套深度的缩进副本。
func MarshalIndent(v any, prefix, indent string) ([]byte, error) {
	var b bytes.Buffer
	enc := NewEncoder(&b)
	enc.Indent(prefix, indent)
	if err := enc.Encode(v); err != nil {
		return nil, err
	}
	return b.Bytes(), nil
}

// 编码器将XML数据写入输出流。
type Encoder struct {
	p printer
}

// NewEncoder返回一个写入w的新编码器。
func NewEncoder(w io.Writer) *Encoder {
	e := &Encoder{printer{Writer: bufio.NewWriter(w)}}
	e.p.encoder = e
	return e
}

// 缩进设置编码器以生成XML，其中每个元素
// 从一个新的缩进行开始，该行以前缀开头，后面跟着
// 根据嵌套深度，缩进的一个或多个副本。
func (enc *Encoder) Indent(prefix, indent string) {
	enc.p.prefix = prefix
	enc.p.indent = indent
}

// Encode将v的XML编码写入流。
// 
// 有关将Go值转换为XML的详细信息，请参阅Marshal文档。
// 
// 返回前对调用进行编码刷新。
func (enc *Encoder) Encode(v any) error {
	err := enc.p.marshalValue(reflect.ValueOf(v), nil, nil)
	if err != nil {
		return err
	}
	return enc.p.Flush()
}

// EncodeElement将v的XML编码写入流，
// 使用start作为编码中最外层的标记。
// 
// 有关将Go值转换为XML的详细信息，请参阅Marshall文档。
// 
// EncodeElement在返回前调用Flush。
func (enc *Encoder) EncodeElement(v any, start StartElement) error {
	err := enc.p.marshalValue(reflect.ValueOf(v), nil, &start)
	if err != nil {
		return err
	}
	return enc.p.Flush()
}

var (
	begComment  = []byte("<!--")
	endComment  = []byte("-->")
	endProcInst = []byte("?>")
)

// EncodeToken将给定的XML标记写入流。
// 如果StartElement和EndElement令牌未正确匹配，则返回错误。
// 
// EncodeToken不调用Flush，因为它通常是更大的操作
// 的一部分，例如Encode或EncodeElement（或在这些操作期间调用
// 的自定义封送处理程序的封送XML），这些操作完成后将调用Flush。
// 如果调用方创建编码器，然后直接调用EncodeToken，而不使用Encode或EncodeElement，则需要在完成时调用Flush，以确保将XML写入底层编写器。
// 
// EncodeToken只允许将目标设置为“xml”的过程写入流中的第一个令牌
// 。
func (enc *Encoder) EncodeToken(t Token) error {

	p := &enc.p
	switch t := t.(type) {
	case StartElement:
		if err := p.writeStart(&t); err != nil {
			return err
		}
	case EndElement:
		if err := p.writeEnd(t.Name); err != nil {
			return err
		}
	case CharData:
		escapeText(p, t, false)
	case Comment:
		if bytes.Contains(t, endComment) {
			return fmt.Errorf("xml: EncodeToken of Comment containing --> marker")
		}
		p.WriteString("<!--")
		p.Write(t)
		p.WriteString("-->")
		return p.cachedWriteError()
	case ProcInst:
		// 要编码的第一个令牌也是一个以xml为目标的过程
		// 是xml声明。唯一允许xml目标的进程。
		if t.Target == "xml" && p.Buffered() != 0 {
			return fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded")
		}
		if !isNameString(t.Target) {
			return fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target")
		}
		if bytes.Contains(t.Inst, endProcInst) {
			return fmt.Errorf("xml: EncodeToken of ProcInst containing ?> marker")
		}
		p.WriteString("<?")
		p.WriteString(t.Target)
		if len(t.Inst) > 0 {
			p.WriteByte(' ')
			p.Write(t.Inst)
		}
		p.WriteString("?>")
	case Directive:
		if !isValidDirective(t) {
			return fmt.Errorf("xml: EncodeToken of Directive containing wrong < or > markers")
		}
		p.WriteString("<!")
		p.Write(t)
		p.WriteString(">")
	default:
		return fmt.Errorf("xml: EncodeToken of invalid token type")

	}
	return p.cachedWriteError()
}

// isValidDirective报告dir是否为有效的指令文本，
// 表示尖括号匹配，忽略注释和字符串。
func isValidDirective(dir Directive) bool {
	var (
		depth     int
		inquote   uint8
		incomment bool
	)
	for i, c := range dir {
		switch {
		case incomment:
			if c == '>' {
				if n := 1 + i - len(endComment); n >= 0 && bytes.Equal(dir[n:i+1], endComment) {
					incomment = false
				}
			}
			// 忽略注释中的任何内容
		case inquote != 0:
			if c == inquote {
				inquote = 0
			}
			// 忽略引号中的任何内容
		case c == '\'' || c == '"':
			inquote = c
		case c == '<':
			if i+len(begComment) < len(dir) && bytes.Equal(dir[i:i+len(begComment)], begComment) {
				incomment = true
			} else {
				depth++
			}
		case c == '>':
			if depth == 0 {
				return false
			}
			depth--
		}
	}
	return depth == 0 && inquote == 0 && !incomment
}

// Flush将所有缓冲的XML刷新到基础编写器。
// 有关何时需要的详细信息，请参阅EncodeToken文档。
func (enc *Encoder) Flush() error {
	return enc.p.Flush()
}

type printer struct {
	*bufio.Writer
	encoder    *Encoder
	seq        int
	indent     string
	prefix     string
	depth      int
	indentedIn bool
	putNewline bool
	attrNS     map[string]string // 映射前缀->名称空间
	attrPrefix map[string]string // 映射名称空间->前缀
	prefixes   []string
	tags       []Name
}

// createAttrPrefix查找要用于给定名称空间的名称空间前缀属性，
// 必要时定义新前缀。它返回前缀。
func (p *printer) createAttrPrefix(url string) string {
	if prefix := p.attrPrefix[url]; prefix != "" {
		return prefix
	}

	// “http:
	// 必须以这种方式引用。
	// ”（http:
	// 但用户不应试图直接使用该文件，这是我们的工作。）
	if url == xmlURL {
		return xmlPrefix
	}

	// 需要定义一个新的名称空间。
	if p.attrPrefix == nil {
		p.attrPrefix = make(map[string]string)
		p.attrNS = make(map[string]string)
	}

	// 选择一个名字。我们尝试使用路径
	// /的最后一个元素，但返回到uz。
	prefix := strings.TrimRight(url, "/")
	if i := strings.LastIndex(prefix, "/"); i >= 0 {
		prefix = prefix[i+1:]
	}
	if prefix == "" || !isName([]byte(prefix)) || strings.Contains(prefix, ":") {
		prefix = "_"
	}
	// xmlanything是保留的，它的任何变体，无论
	// 大小写，都应该匹配，所以：
	// （（'X'|'X'）（'M'|'M'）（'L'|'L'））
	// 请参阅https:
	if len(prefix) >= 3 && strings.EqualFold(prefix[:3], "xml") {
		prefix = "_" + prefix
	}
	if p.attrNS[prefix] != "" {
		// 的第2.3节。找一个更好的。
		for p.seq++; ; p.seq++ {
			if id := prefix + "_" + strconv.Itoa(p.seq); p.attrNS[id] == "" {
				prefix = id
				break
			}
		}
	}

	p.attrPrefix[url] = prefix
	p.attrNS[prefix] = url

	p.WriteString(`xmlns:`)
	p.WriteString(prefix)
	p.WriteString(`="`)
	EscapeText(p, []byte(url))
	p.WriteString(`" `)

	p.prefixes = append(p.prefixes, prefix)

	return prefix
}

// deleteAttrPrefix删除属性名称空间前缀。
func (p *printer) deleteAttrPrefix(prefix string) {
	delete(p.attrPrefix, p.attrNS[prefix])
	delete(p.attrNS, prefix)
}

func (p *printer) markPrefix() {
	p.prefixes = append(p.prefixes, "")
}

func (p *printer) popPrefix() {
	for len(p.prefixes) > 0 {
		prefix := p.prefixes[len(p.prefixes)-1]
		p.prefixes = p.prefixes[:len(p.prefixes)-1]
		if prefix == "" {
			break
		}
		p.deleteAttrPrefix(prefix)
	}
}

var (
	marshalerType     = reflect.TypeOf((*Marshaler)(nil)).Elem()
	marshalerAttrType = reflect.TypeOf((*MarshalerAttr)(nil)).Elem()
	textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
)

// MarshallValue写入一个或多个表示val的XML元素。
// 如果val是从结构字段获取的，则finfo必须有其详细信息。
func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplate *StartElement) error {
	if startTemplate != nil && startTemplate.Name.Local == "" {
		return fmt.Errorf("xml: EncodeElement of StartElement with missing name")
	}

	if !val.IsValid() {
		return nil
	}
	if finfo != nil && finfo.flags&fOmitEmpty != 0 && isEmptyValue(val) {
		return nil
	}

	// 深入研究接口和指针。
	// 给定一个循环链，这可以变成一个无限循环，但它与Go 1行为相匹配。
	for val.Kind() == reflect.Interface || val.Kind() == reflect.Pointer {
		if val.IsNil() {
			return nil
		}
		val = val.Elem()
	}

	kind := val.Kind()
	typ := val.Type()

	// 检查封送员。
	if val.CanInterface() && typ.Implements(marshalerType) {
		return p.marshalInterface(val.Interface().(Marshaler), defaultStart(typ, finfo, startTemplate))
	}
	if val.CanAddr() {
		pv := val.Addr()
		if pv.CanInterface() && pv.Type().Implements(marshalerType) {
			return p.marshalInterface(pv.Interface().(Marshaler), defaultStart(pv.Type(), finfo, startTemplate))
		}
	}

	// 检查文本封送器。
	if val.CanInterface() && typ.Implements(textMarshalerType) {
		return p.marshalTextInterface(val.Interface().(encoding.TextMarshaler), defaultStart(typ, finfo, startTemplate))
	}
	if val.CanAddr() {
		pv := val.Addr()
		if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
			return p.marshalTextInterface(pv.Interface().(encoding.TextMarshaler), defaultStart(pv.Type(), finfo, startTemplate))
		}
	}

	// 切片和数组在元素上迭代。它们没有封闭标签。
	if (kind == reflect.Slice || kind == reflect.Array) && typ.Elem().Kind() != reflect.Uint8 {
		for i, n := 0, val.Len(); i < n; i++ {
			if err := p.marshalValue(val.Index(i), finfo, startTemplate); err != nil {
				return err
			}
		}
		return nil
	}

	tinfo, err := getTypeInfo(typ)
	if err != nil {
		return err
	}

	// 创建开始元素。
	// XML元素名的优先级为：
	// 0。startTemplate 
	// 1。基础结构中的XMLName字段；
	// 2。结构字段中的字段名/标记；和
	// 3。类型名称
	var start StartElement

	if startTemplate != nil {
		start.Name = startTemplate.Name
		start.Attr = append(start.Attr, startTemplate.Attr...)
	} else if tinfo.xmlname != nil {
		xmlname := tinfo.xmlname
		if xmlname.name != "" {
			start.Name.Space, start.Name.Local = xmlname.xmlns, xmlname.name
		} else {
			fv := xmlname.value(val, dontInitNilPointers)
			if v, ok := fv.Interface().(Name); ok && v.Local != "" {
				start.Name = v
			}
		}
	}
	if start.Name.Local == "" && finfo != nil {
		start.Name.Space, start.Name.Local = finfo.xmlns, finfo.name
	}
	if start.Name.Local == "" {
		name := typ.Name()
		if i := strings.IndexByte(name, '['); i >= 0 {
			// 截断泛型实例化名称。见第48318期。
			name = name[:i]
		}
		if name == "" {
			return &UnsupportedTypeError{typ}
		}
		start.Name.Local = name
	}

	// Attributes 
	for i := range tinfo.fields {
		finfo := &tinfo.fields[i]
		if finfo.flags&fAttr == 0 {
			continue
		}
		fv := finfo.value(val, dontInitNilPointers)

		if finfo.flags&fOmitEmpty != 0 && (!fv.IsValid() || isEmptyValue(fv)) {
			continue
		}

		if fv.Kind() == reflect.Interface && fv.IsNil() {
			continue
		}

		name := Name{Space: finfo.xmlns, Local: finfo.name}
		if err := p.marshalAttr(&start, name, fv); err != nil {
			return err
		}
	}

	if err := p.writeStart(&start); err != nil {
		return err
	}

	if val.Kind() == reflect.Struct {
		err = p.marshalStruct(tinfo, val)
	} else {
		s, b, err1 := p.marshalSimple(typ, val)
		if err1 != nil {
			err = err1
		} else if b != nil {
			EscapeText(p, b)
		} else {
			p.EscapeString(s)
		}
	}
	if err != nil {
		return err
	}

	if err := p.writeEnd(start.Name); err != nil {
		return err
	}

	return p.cachedWriteError()
}

// marshalAttr使用给定的名称和值封送属性，并添加到开始。Attr。
func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value) error {
	if val.CanInterface() && val.Type().Implements(marshalerAttrType) {
		attr, err := val.Interface().(MarshalerAttr).MarshalXMLAttr(name)
		if err != nil {
			return err
		}
		if attr.Name.Local != "" {
			start.Attr = append(start.Attr, attr)
		}
		return nil
	}

	if val.CanAddr() {
		pv := val.Addr()
		if pv.CanInterface() && pv.Type().Implements(marshalerAttrType) {
			attr, err := pv.Interface().(MarshalerAttr).MarshalXMLAttr(name)
			if err != nil {
				return err
			}
			if attr.Name.Local != "" {
				start.Attr = append(start.Attr, attr)
			}
			return nil
		}
	}

	if val.CanInterface() && val.Type().Implements(textMarshalerType) {
		text, err := val.Interface().(encoding.TextMarshaler).MarshalText()
		if err != nil {
			return err
		}
		start.Attr = append(start.Attr, Attr{name, string(text)})
		return nil
	}

	if val.CanAddr() {
		pv := val.Addr()
		if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
			text, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
			if err != nil {
				return err
			}
			start.Attr = append(start.Attr, Attr{name, string(text)})
			return nil
		}
	}

	// 取消引用或跳过零指针，接口值。
	switch val.Kind() {
	case reflect.Pointer, reflect.Interface:
		if val.IsNil() {
			return nil
		}
		val = val.Elem()
	}

	// 步行切片。
	if val.Kind() == reflect.Slice && val.Type().Elem().Kind() != reflect.Uint8 {
		n := val.Len()
		for i := 0; i < n; i++ {
			if err := p.marshalAttr(start, name, val.Index(i)); err != nil {
				return err
			}
		}
		return nil
	}

	if val.Type() == attrType {
		start.Attr = append(start.Attr, val.Interface().(Attr))
		return nil
	}

	s, b, err := p.marshalSimple(val.Type(), val)
	if err != nil {
		return err
	}
	if b != nil {
		s = string(b)
	}
	start.Attr = append(start.Attr, Attr{name, s})
	return nil
}

// defaultStart返回要使用的默认开始元素，
// 给定反射类型、字段信息和开始模板。
func defaultStart(typ reflect.Type, finfo *fieldInfo, startTemplate *StartElement) StartElement {
	var start StartElement
	// XML元素名的优先级如上所述，
	// 只是我们不在结构内部查找第一个字段。
	if startTemplate != nil {
		start.Name = startTemplate.Name
		start.Attr = append(start.Attr, startTemplate.Attr...)
	} else if finfo != nil && finfo.name != "" {
		start.Name.Local = finfo.name
		start.Name.Space = finfo.xmlns
	} else if typ.Name() != "" {
		start.Name.Local = typ.Name()
	} else {
		// 必须是指向命名类型
		// 的指针，因为它具有封送处理程序方法。
		start.Name.Local = typ.Elem().Name()
	}
	return start
}

// 封送接口封送一个封送器接口值。
func (p *printer) marshalInterface(val Marshaler, start StartElement) error {
	// 将标记推到标记堆栈上，以便MarshalXML 
	// 无法关闭未打开的XML标记。
	p.tags = append(p.tags, Name{})
	n := len(p.tags)

	err := val.MarshalXML(p.encoder, start)
	if err != nil {
		return err
	}

	// 确保MarshalXML关闭了所有标记。p、 标记[n-1]是标记。
	if len(p.tags) > n {
		return fmt.Errorf("xml: %s.MarshalXML wrote invalid XML: <%s> not closed", receiverType(val), p.tags[len(p.tags)-1].Local)
	}
	p.tags = p.tags[:n-1]
	return nil
}

// marshalTextInterface封送一个TextMarshaler接口值。
func (p *printer) marshalTextInterface(val encoding.TextMarshaler, start StartElement) error {
	if err := p.writeStart(&start); err != nil {
		return err
	}
	text, err := val.MarshalText()
	if err != nil {
		return err
	}
	EscapeText(p, text)
	return p.writeEnd(start.Name)
}

// writeStart写入给定的开始元素。
func (p *printer) writeStart(start *StartElement) error {
	if start.Name.Local == "" {
		return fmt.Errorf("xml: start tag with no name")
	}

	p.tags = append(p.tags, start.Name)
	p.markPrefix()

	p.writeIndent(1)
	p.WriteByte('<')
	p.WriteString(start.Name.Local)

	if start.Name.Space != "" {
		p.WriteString(` xmlns="`)
		p.EscapeString(start.Name.Space)
		p.WriteByte('"')
	}

	// 属性
	for _, attr := range start.Attr {
		name := attr.Name
		if name.Local == "" {
			continue
		}
		p.WriteByte(' ')
		if name.Space != "" {
			p.WriteString(p.createAttrPrefix(name.Space))
			p.WriteByte(':')
		}
		p.WriteString(name.Local)
		p.WriteString(`="`)
		p.EscapeString(attr.Value)
		p.WriteByte('"')
	}
	p.WriteByte('>')
	return nil
}

func (p *printer) writeEnd(name Name) error {
	if name.Local == "" {
		return fmt.Errorf("xml: end tag with no name")
	}
	if len(p.tags) == 0 || p.tags[len(p.tags)-1].Local == "" {
		return fmt.Errorf("xml: end tag </%s> without start tag", name.Local)
	}
	if top := p.tags[len(p.tags)-1]; top != name {
		if top.Local != name.Local {
			return fmt.Errorf("xml: end tag </%s> does not match start tag <%s>", name.Local, top.Local)
		}
		return fmt.Errorf("xml: end tag </%s> in namespace %s does not match start tag <%s> in namespace %s", name.Local, name.Space, top.Local, top.Space)
	}
	p.tags = p.tags[:len(p.tags)-1]

	p.writeIndent(-1)
	p.WriteByte('<')
	p.WriteByte('/')
	p.WriteString(name.Local)
	p.WriteByte('>')
	p.popPrefix()
	return nil
}

func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) (string, []byte, error) {
	switch val.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return strconv.FormatInt(val.Int(), 10), nil, nil
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return strconv.FormatUint(val.Uint(), 10), nil, nil
	case reflect.Float32, reflect.Float64:
		return strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()), nil, nil
	case reflect.String:
		return val.String(), nil, nil
	case reflect.Bool:
		return strconv.FormatBool(val.Bool()), nil, nil
	case reflect.Array:
		if typ.Elem().Kind() != reflect.Uint8 {
			break
		}
		// /[…]字节
		var bytes []byte
		if val.CanAddr() {
			bytes = val.Slice(0, val.Len()).Bytes()
		} else {
			bytes = make([]byte, val.Len())
			reflect.Copy(reflect.ValueOf(bytes), val)
		}
		return "", bytes, nil
	case reflect.Slice:
		if typ.Elem().Kind() != reflect.Uint8 {
			break
		}
		// /[]字节
		return "", val.Bytes(), nil
	}
	return "", nil, &UnsupportedTypeError{typ}
}

var ddBytes = []byte("--")

// 间接钻取接口和指针，返回指向的值。
// 如果遇到nil接口或指针，则间接返回该nil值。
// 给定一个循环链，这可以变成一个无限循环，但它符合Go 1行为。
func indirect(vf reflect.Value) reflect.Value {
	for vf.Kind() == reflect.Interface || vf.Kind() == reflect.Pointer {
		if vf.IsNil() {
			return vf
		}
		vf = vf.Elem()
	}
	return vf
}

func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
	s := parentStack{p: p}
	for i := range tinfo.fields {
		finfo := &tinfo.fields[i]
		if finfo.flags&fAttr != 0 {
			continue
		}
		vf := finfo.value(val, dontInitNilPointers)
		if !vf.IsValid() {
			// 该字段位于匿名结构字段后面，该字段为
			// nil。跳过它。
			continue
		}

		switch finfo.flags & fMode {
		case fCDATA, fCharData:
			emit := EscapeText
			if finfo.flags&fMode == fCDATA {
				emit = emitCDATA
			}
			if err := s.trim(finfo.parents); err != nil {
				return err
			}
			if vf.CanInterface() && vf.Type().Implements(textMarshalerType) {
				data, err := vf.Interface().(encoding.TextMarshaler).MarshalText()
				if err != nil {
					return err
				}
				if err := emit(p, data); err != nil {
					return err
				}
				continue
			}
			if vf.CanAddr() {
				pv := vf.Addr()
				if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
					data, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
					if err != nil {
						return err
					}
					if err := emit(p, data); err != nil {
						return err
					}
					continue
				}
			}

			var scratch [64]byte
			vf = indirect(vf)
			switch vf.Kind() {
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				if err := emit(p, strconv.AppendInt(scratch[:0], vf.Int(), 10)); err != nil {
					return err
				}
			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
				if err := emit(p, strconv.AppendUint(scratch[:0], vf.Uint(), 10)); err != nil {
					return err
				}
			case reflect.Float32, reflect.Float64:
				if err := emit(p, strconv.AppendFloat(scratch[:0], vf.Float(), 'g', -1, vf.Type().Bits())); err != nil {
					return err
				}
			case reflect.Bool:
				if err := emit(p, strconv.AppendBool(scratch[:0], vf.Bool())); err != nil {
					return err
				}
			case reflect.String:
				if err := emit(p, []byte(vf.String())); err != nil {
					return err
				}
			case reflect.Slice:
				if elem, ok := vf.Interface().([]byte); ok {
					if err := emit(p, elem); err != nil {
						return err
					}
				}
			}
			continue

		case fComment:
			if err := s.trim(finfo.parents); err != nil {
				return err
			}
			vf = indirect(vf)
			k := vf.Kind()
			if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) {
				return fmt.Errorf("xml: bad type for comment field of %s", val.Type())
			}
			if vf.Len() == 0 {
				continue
			}
			p.writeIndent(0)
			p.WriteString("<!--")
			dashDash := false
			dashLast := false
			switch k {
			case reflect.String:
				s := vf.String()
				dashDash = strings.Contains(s, "--")
				dashLast = s[len(s)-1] == '-'
				if !dashDash {
					p.WriteString(s)
				}
			case reflect.Slice:
				b := vf.Bytes()
				dashDash = bytes.Contains(b, ddBytes)
				dashLast = b[len(b)-1] == '-'
				if !dashDash {
					p.Write(b)
				}
			default:
				panic("can't happen")
			}
			if dashDash {
				return fmt.Errorf(`xml: comments must not contain "--"`)
			}
			if dashLast {
				// /“-->”是无效语法。设置为“--->”
				p.WriteByte(' ')
			}
			p.WriteString("-->")
			continue

		case fInnerXML:
			vf = indirect(vf)
			iface := vf.Interface()
			switch raw := iface.(type) {
			case []byte:
				p.Write(raw)
				continue
			case string:
				p.WriteString(raw)
				continue
			}

		case fElement, fElement | fAny:
			if err := s.trim(finfo.parents); err != nil {
				return err
			}
			if len(finfo.parents) > len(s.stack) {
				if vf.Kind() != reflect.Pointer && vf.Kind() != reflect.Interface || !vf.IsNil() {
					if err := s.push(finfo.parents[len(s.stack):]); err != nil {
						return err
					}
				}
			}
		}
		if err := p.marshalValue(vf, finfo, nil); err != nil {
			return err
		}
	}
	s.trim(nil)
	return p.cachedWriteError()
}

// 返回bufio写入程序的缓存写入错误
func (p *printer) cachedWriteError() error {
	_, err := p.Write(nil)
	return err
}

func (p *printer) writeIndent(depthDelta int) {
	if len(p.prefix) == 0 && len(p.indent) == 0 {
		return
	}
	if depthDelta < 0 {
		p.depth--
		if p.indentedIn {
			p.indentedIn = false
			return
		}
		p.indentedIn = false
	}
	if p.putNewline {
		p.WriteByte('\n')
	} else {
		p.putNewline = true
	}
	if len(p.prefix) > 0 {
		p.WriteString(p.prefix)
	}
	if len(p.indent) > 0 {
		for i := 0; i < p.depth; i++ {
			p.WriteString(p.indent)
		}
	}
	if depthDelta > 0 {
		p.depth++
		p.indentedIn = true
	}
}

type parentStack struct {
	p     *printer
	stack []string
}

// trim更新XML上下文，以匹配堆栈
// 和给定父级的最长公共前缀。将为每个弹出的父
// 写一个结束标记。传递零片或零将关闭所有元素。
func (s *parentStack) trim(parents []string) error {
	split := 0
	for ; split < len(parents) && split < len(s.stack); split++ {
		if parents[split] != s.stack[split] {
			break
		}
	}
	for i := len(s.stack) - 1; i >= split; i-- {
		if err := s.p.writeEnd(Name{Local: s.stack[i]}); err != nil {
			return err
		}
	}
	s.stack = s.stack[:split]
	return nil
}

// push将父元素添加到堆栈并写入打开的标记。
func (s *parentStack) push(parents []string) error {
	for i := 0; i < len(parents); i++ {
		if err := s.p.writeStart(&StartElement{Name: Name{Local: parents[i]}}); err != nil {
			return err
		}
	}
	s.stack = append(s.stack, parents...)
	return nil
}

// 当封送遇到无法转换为XML的类型
// 时，返回UnsupportedTypeError。
type UnsupportedTypeError struct {
	Type reflect.Type
}

func (e *UnsupportedTypeError) Error() string {
	return "xml: unsupported type: " + e.Type.String()
}

func isEmptyValue(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		return v.Len() == 0
	case reflect.Bool:
		return !v.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Interface, reflect.Pointer:
		return v.IsNil()
	}
	return false
}
